import sys
import numpy as np
import tree
import node
import cplex
#from cplex.exceptions import CplexError

def branchbound(c):
    c.parameters.output.writelevel.set(0)
    c.parameters.simplex.display.set(0)

    rt = node.root(c) 
    tr = tree.tree(rt)
    #tr.setup()
    iter = 0
    
    while True:
        #-- we need to check limit 

        if iter >= 200:
            break
        if len(tr.nodeq) == 0:
            print "node q is empty"
            break
        
        iter = iter + 1
        #-- get node from the tree
        nd = tr.pop()
        #-- solve the node LP
        nd.solve_lp()

        # need better log information
        print 
        print "--------------"
        print "Iteration ", iter
        print "node index", nd.node_ind
        #print "node counts", nd.node_cnt[0]
        print "objvalue", nd.z
        print "current bound", nd.global_info["bound"]
        print "current incumbent", nd.global_info["incumbent"]
        print "objsolution", nd.lp.solution.get_values()
        print "depth", nd.depth
        print "lower bounds", nd.lo_bnds
        print "lower bounds varialbes", nd.lo_vars
        print "Upper bounds", nd.up_bnds
        print "Upper bounds variables", nd.up_vars
        print "Queue length", len(tr.nodeq)
        print "--------------"

        if nd.fathom_by_feasibility():
            print "fathom by feasibility"
            continue
        elif nd.fathom_by_optimality():
            print "fathom by optimality"
            continue
        elif nd.fathom_by_bound():
            print "fathom by bound"
            continue
        else:
            # nd.update_global_bound()
            tr.branch(nd)

    print "Optimal solution is", nd.global_info["incumbent"]


    """
    if not nd.test_feasibility():
    #tree.update_global_bounds (nd)
    nd.fathom()
    #continue
    elif nd.test_integer():
    #tr.update_global_bounds (nd)
    nd.fathom()
    #continue
    elif nd.test_bound():
    #    tr.update_global_bounds (nd)
    #    nd.fathom()
    #    continue
    else:
    tr.branch(nd)
    """
        
        #-- (we can check the bound here, but for simplicity today
        #-- we go strait to branching)

        #-- acoordinng to the status flag of the node
        #-- three states
        #-- 1. Infeasible: node.update
        #-- 2. Integer feasible
        #-- 3. Optimal noninteger
        #--    3.1 fathom by bound
        #--    3.2 branch

        #-- node.status
        #-- tree.update_xxx
        #-- tree.update_incumbent(node)
        #-- tree.update_bound(node)
        #-- tree.branch(node)
        #
        #print 
        # check the solution status
        #if c.solution.get_status() == 3:
            # fathom by infeasibility
            # get solution at node LP
            #-- test integer feasibility
#End of while loop

def branchbound_batch(c):
    c.parameters.output.writelevel.set(0)
    c.parameters.simplex.display.set(0)

    rt = node.root(c) 
    tr = tree.tree(rt)
    iter = 0
    
    while True:
        if iter >= 500:
            break
        if len(tr.nodeq) == 0:
            break
        
        iter = iter + 1
        nd = tr.pop()
        nd.solve_lp()

        if nd.fathom_by_feasibility():
            continue
        elif nd.fathom_by_optimality():
            continue
        elif nd.fathom_by_bound():
            continue
        else:
            #tr.branch(nd)
            nd.branch(tr)

    return nd.global_info, iter
           
def report(solution, iter):
    print "%20s "  % solution["problem"],
    print "%18.6f" % solution["incumbent"],
    print "%10i"   % solution["nodecnt"],
    print "%10i"   % iter


    #print "Optimal solution is", nd.global_info["incumbent"]
#c = cplex.Cplex(" ")
#branchbound()
